﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Diagnostics;

namespace Engine.Dtd.Schema {
    /// <summary>
    /// An attribute definition in a DTD.
    /// </summary>
    [DebuggerDisplay("{Name} {AttributeType} {Presence}")]
    public sealed class DAttribute {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private DName name;
        /// <summary>
        /// Initializes a new instance of the <see cref="DAttribute"/> class.
        /// </summary>
        /// <param name="name">The name of the attribute.</param>
        internal DAttribute(DName name) {
            Guard.ArgumentNotNull(name, "name");
            this.name = name;
            }

        /// <summary>
        /// Gets the name of the attribute declared by this attribute definition.
        /// </summary>
        public DName Name {
            get { return name; }
            }

        /// <summary>
        /// Gets of sets the default value of the attribute.
        /// </summary>
        public string Default { get; set; }

        /// <summary>
        /// Gets the constraints on the attribute's presence on an element.
        /// </summary>
        public DAttributePresence Presence { get; internal set; }

        /// <summary>
        /// Gets the type of an attribute declaration.
        /// </summary>
        public DAttributeType AttributeType { get; internal set; }

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private string[] values;
        /// <summary>
        /// Gets the possible enumerated values for the attribute.
        /// </summary>
        /// <returns>A System.String array that contains the values associated with this SAttribute if exist; otherwise, null.</returns>
        public string[] GetEnumeratedValues() {
            return values;
            }

        /// <summary>
        /// Sets the attribute definition to have an enumerated value.
        /// </summary>
        /// <param name="values">The possible values in the enumeration.</param>
        /// <exception cref="System.ArgumentNullException">ArgumentNullException</exception>
        internal void Initialize(string[] values) {
            Guard.ArgumentNotNull(values, "values");
            this.values = values;
            AttributeType = DAttributeType.Enumeration;
            }

        /// <summary>
        /// Convert the specified token to an DAttributeType instance.
        /// </summary>
        /// <param name="token">A string representation of the attribute type, corresponding to the values in the <see cref="DAttributeType"/> enumeration.</param>
        /// <exception cref="ArgumentNullException">ArgumentNullException. If token is null.</exception>
        /// <exception cref="DtdException">DtdException. If token is not a valid <see cref="DAttributeType"/> value.</exception>
        /// <returns>An DAttributeType instance.</returns>
        public static DAttributeType ParseType(string token) {
            Guard.ArgumentNotNull(token, "type");
            switch (token) {
                case "CDATA":
                    return DAttributeType.CData;
                case "ENTITY":
                    return DAttributeType.Entity;
                case "ENTITIES":
                    return DAttributeType.Entities;
                case "ID":
                    return DAttributeType.Id;
                case "IDREF":
                    return DAttributeType.IdRef;
                case "IDREFS":
                    return DAttributeType.IdRefs;
                case "NAME":
                    return DAttributeType.Name;
                case "NAMES":
                    return DAttributeType.NameList;
                case "NMTOKEN":
                    return DAttributeType.NmToken;
                case "NMTOKENS":
                    return DAttributeType.NmTokenList;
                case "NUMBER":
                    return DAttributeType.Number;
                case "NUMBERS":
                    return DAttributeType.NumberList;
                case "NUTOKEN":
                    return DAttributeType.NumberToken;
                case "NUTOKENS":
                    return DAttributeType.NumberTokenList;
                default:
                    throw new DtdException(string.Format(CultureInfo.CurrentUICulture, "Attribute type '{0}' is not supported", token));
                }
            }

        /// <summary>
        /// Converts the specified token to an DAttributePresence instance.
        /// </summary>
        /// <param name="token">A string representation of the attribute presence, corresponding to one of the values in the <see cref="DAttributePresence"/> enumeration.</param>
        /// <exception cref="ArgumentException">ArgumentException. If token is null.</exception>
        /// <exception cref="DtdException">DtdException. If token is not a valid <see cref="DAttributePresence"/> value.</exception>
        /// <returns>An DAttributePresence instance.</returns>
        public static DAttributePresence ParsePresence(string token) {
            Guard.ArgumentNotNull(token, "token");
            if (string.Equals(token, "FIXED", StringComparison.InvariantCultureIgnoreCase))
                return DAttributePresence.Fixed;
            else if (string.Equals(token, "REQUIRED", StringComparison.InvariantCultureIgnoreCase))
                return DAttributePresence.Required;
            else if (string.Equals(token, "IMPLIED", StringComparison.InvariantCultureIgnoreCase))
                return DAttributePresence.Implied;
            else
                throw new DtdException(String.Format(CultureInfo.CurrentUICulture, "Attribute value '{0}' not supported", token));
            }
        }
    }
